#pragma once 
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <strings.h>
#include <string>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <fstream>

#define HTTP_VERSION "HTTP/1.0"
#define HOME_PATH "wwwroot/index.html"
namespace ns_httpServer {
    class HttpServer {
        private:
            uint16_t port;
            int listen_sock;
        public:
            HttpServer(uint16_t _port) 
                :port(_port)
                ,listen_sock(-1)
            {}
            ~HttpServer() {
                if (listen_sock > 0) {
                    close(listen_sock);
                }
            }
            void initHttpServer() {
                listen_sock = socket(AF_INET, SOCK_STREAM, 0);
                if (listen_sock < 0) {
                    exit(2);
                }
                struct sockaddr_in local;
                bzero(&local, sizeof(local));
                local.sin_family = AF_INET;
                local.sin_port = htons(port);
                local.sin_addr.s_addr = htonl(INADDR_ANY);
                if (bind(listen_sock, (struct sockaddr*)&local, sizeof(local)) < 0) {
                    std::cerr << "bind error " << std::endl;
                    exit(3);
                }
                if (listen(listen_sock, 5) < 0) {
                    std::cerr << "listen error " << std::endl;
                    exit(4);
                }
            }

            static void* HandlerServer(void *args) {
                pthread_detach(pthread_self());
                int sock = *(int*)args;
                delete (int*)args;
                // get request
                // std::cout << "######################################## begin" << sock << "######" << std::endl;
                char buffer[4096] = {0};
                ssize_t s = recv(sock, buffer, sizeof(buffer), 0);
                if (s > 0) {
                    buffer[s] = 0;
                    std::cout << buffer;
                }
                // make response
                // std::string response = HTTP_VERSION;
                // response += "200 OK\n";
                // response += "Content-Type: text/html\n";
                // std::string body = "<html><head><meta charset=\"UTF-8\"></head><body><h1>hello world</h1></body></html>";
                // response += ("Content-Length: " + std::to_string(body.size()) + "\n");
                // response += "\n";  // 空行用来区分有效载荷和报头
                // response += body;

                std::string body;
                std::string response;
                std::ifstream in(HOME_PATH, std::ios::in | std::ios::binary);
                if (!in.is_open()) {

                } else {
                    std::string line;
                    while (getline(in, line)) {
                        body += line;
                    }
                    response += HTTP_VERSION;
                    response += "200 OK\n";
                    response += "Content-Type: text/html\n";
                    response += ("Content-Length: " + std::to_string(body.size()) + "\n");
                    response += "\n";  // 空行用来区分有效载荷和报头
                    response += body;
                }
                in.close();
                send(sock, response.c_str(), response.size(), 0);
                close(sock);   // 接收一次响应一次就关闭，短链接
                // std::cout << "######################################## end" << sock << "######" << std::endl;
                return nullptr;
            }

            void Loop() {
                while (true) {
                    struct sockaddr_in peer;
                    socklen_t len = sizeof(peer);
                    int sock = accept(listen_sock, (struct sockaddr*)&peer, &len);
                    if (sock < 0) {
                        std::cerr << "accept error " << std::endl;
                        exit(5);
                    } 
                    pthread_t tid;
                    int *p = new int(sock);
                    pthread_create(&tid, nullptr, HandlerServer, p);
                }

            }
    };
}
